
#include "lfs.h"
#include "assert.h"
#include "w25qxx.h"

#include "fsapi.h"
#include "platform.h"
#include <stdio.h>
#include <string.h>

static lfs_t lfs; //lfs file system
static os_mutex_t lfs_mutex = NULL;
static int user_provided_block_device_read(const struct lfs_config *lfsc, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
{
    os_mutex_lock(&lfs_mutex);
    W25QXX_Read((uint8_t *)buffer,(block * lfsc->block_size + off),size); 
    os_mutex_unlock(&lfs_mutex);
    return LFS_ERR_OK;
}

static int user_provided_block_device_prog(const struct lfs_config *lfsc, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
{
    os_mutex_lock(&lfs_mutex);
    W25QXX_Write_NoCheck((uint8_t*)buffer,(block * lfsc->block_size + off),size);
    os_mutex_unlock(&lfs_mutex);
    return LFS_ERR_OK;
}

static int user_provided_block_device_erase(const struct lfs_config *lfsc, lfs_block_t block)
{
    os_mutex_lock(&lfs_mutex);
    W25QXX_Erase_Sector(block);
    os_mutex_unlock(&lfs_mutex);
    return LFS_ERR_OK;
}
static int user_provided_block_device_sync(const struct lfs_config *lfsc)
{
    return LFS_ERR_OK;
}

//uint8_t lfs_read_buf[256];
//uint8_t lfs_prog_buf[256];
//uint8_t lfs_lookahead_buf[16];	
//uint8_t lfs_file_buf[256];


const struct lfs_config cfg = {
    // block device driver context data
    .context = 0,
    // block device operations
    .read  = user_provided_block_device_read, //read data
    .prog  = user_provided_block_device_prog, //program block
    .erase = user_provided_block_device_erase,//erase block
    .sync  = user_provided_block_device_sync,

    //block device configuration
    .read_size = 256,
    .prog_size = 256,
    .block_size = 4096,
    .block_count = 4096,
    .cache_size = 256,
    .lookahead_size = 256, //32 integer multiple
    .block_cycles = 500,
    
    .read_buffer = NULL, //lfs_read_buf,
    .prog_buffer = NULL, //lfs_prog_buf,
    .lookahead_buffer = NULL, //lfs_lookahead_buf,
};

void fs_init(void)
{
    W25QXX_Init(); 
    lfs_mutex = os_mutex_create();
    int err = lfs_mount(&lfs, &cfg);

    // reformat if we can't mount the filesystem
    // this should only happen on the first boot
    if (err)
    {
    lfs_format(&lfs, &cfg);
    lfs_mount(&lfs, &cfg);
    }
}

int fs_open(fs_fd *fd, const char *path, unsigned int mode){
  return lfs_file_open(&lfs, fd, path,mode);
}

int fs_write(fs_fd *fd, char *buf, int len){
  return lfs_file_write(&lfs, fd, buf,len);
}

int fs_read(fs_fd *fd, char *buf, int len){
  return lfs_file_read(&lfs, fd, buf, len);
}

int fs_read_line(fs_fd *fd, char *buf, int len){
    if (fs_size(fd) <= 0){
        return 0;
    }
    
    char_t ch;
    int32_t i = 0;
    
    while(1){
        if (i >= (len-1)){
            break;
        }
        if (fs_read(fd, &ch, 1) <= 0){
            break;
        }
        if (((ch == '\n') && (i != 0)) || (ch == 0)){
            break;
        }
        if (ch != '\r'){
            buf[i++] = ch;
        }
    }
    return i;
}

int fs_truncate(fs_fd *fd, int len){
  return lfs_file_truncate(&lfs, fd, len);
}

int fs_delete(const char *path){
  return lfs_remove(&lfs,path);
}
int fs_close(fs_fd *fd){
  return lfs_file_close(&lfs, fd);
}
//返回 0 不存在 1 存在
int fs_exist(const char *path){
    int ret  = 0;
    struct lfs_info info;
    ret = lfs_stat(&lfs, path,&info);
    if(ret ==LFS_ERR_NOENT)
    {
        return 0;
    }
    return 1;
}

int fs_lseek(fs_fd *fd, int pos, int mode){
  return lfs_file_seek(&lfs, fd, pos, mode);
}

int fs_size(fs_fd *fd){
  return lfs_file_size(&lfs, fd);
}

int fs_rename(char *old_path, char *new_path){
  return lfs_rename(&lfs, old_path, new_path);
}

int fs_sync(fs_fd *fd){
  return 0;
}

int fs_ls(const char_t *path)
{
    int32_t ret = 0;
    lfs_dir_t dir;
    struct lfs_info info;
    ret = lfs_dir_open(&lfs, &dir, path);
    if (ret < 0){
        printf("open dir %s fail\r\n", path);
        return -1;
    }
    printf("************************************************************\r\n");
    printf("type        size        name\r\n");
    while(1)
    {   
        lfs_dir_read(&lfs, &dir, &info);
        if (info.type == 0)
        {
            break;
        }
        printf("%4d   %8d           %s\r\n", info.type,info.size,info.name);
        //printf("lfs get ./ file info type = %d size = %d  filename = %s \r\n",info.type,info.size,info.name);
    }
    printf("\r\n");
    lfs_dir_close(&lfs, &dir);
    return 0;
}

int fs_cat(const char *name) {
    fs_fd fd;
    char *buf = 0;
    if (fs_exist(name)) {
        if (fs_open(&fd, name, (uint32_t)LFS_O_RDWR) == (int)LFS_ERR_OK) {
					  uint32_t size = fs_size(&fd);
					  buf = (char *)os_malloc(size+1);
            memset(buf,0,size+1);				   
					
            fs_lseek(&fd, 0, FS_SEEK_SET);
            fs_read(&fd, buf,size);
            printf("%s\r\n", buf);
            //for(uint32_t i = 0; i < sizeof(buf); i++) {
            //    printf("%02x", buf[i]);
            //}
					  os_free(buf);
            fs_close(&fd);
        }
    } else {
        printf("file: %s not exist\r\n", name);
    }
    return 0;
}

int fs_mkdir(const char *path){
    return lfs_mkdir(&lfs, path);
}


int fs_file_list(const char_t *path, char_t *name_list, int32_t name_len, int32_t cnt){
    int32_t ret = 0;
    int32_t i = 0;
    lfs_dir_t dir;
    struct lfs_info info;
    
    ret = lfs_dir_open(&lfs, &dir, path);
    if (ret < 0) {
        printf("open dir %s fail\r\n", path);
        return -1;
    }

    while(1) {   
        lfs_dir_read(&lfs, &dir, &info);
        if (info.type == 0) {
            break;
        }
        
        if ((info.type == 1) && (info.size != 0)) {
            strncpy(name_list+name_len*i, info.name, name_len);
            i++;
        }
        
        if (i >= cnt){
            break;
        }
        
        //printf("%4d   %8d           %s\r\n", info.type,info.size,info.name);
    }
    
    lfs_dir_close(&lfs, &dir);
    return i;

}


int fs_format(void){
    return lfs_format(&lfs, &cfg);
}





